-module(crc).
-export([calculateCRC/1, checkCRC/2]).

%% ----------------
%% 验证CRC
%% return true or false
checkCRC(BinList, Crc) ->
    case calculateCRC(BinList) of
        Crc ->
            true;
        _ ->
            false
    end.


%% ----------------
%% 计算CRC
%% {HighByte, LowByte}
calculateCRC(BinList) ->
    LookupCRCHi = [ 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80,
            16#41, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01,
            16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80,
            16#41, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#01,
            16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81,
            16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01,
            16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81,
            16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00,
            16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80,
            16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00,
            16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80,
            16#41, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#01,
            16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80,
            16#41, 16#00, 16#C1, 16#81, 16#40, 16#00, 16#C1, 16#81, 16#40, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40, 16#01,
            16#C0, 16#80, 16#41, 16#01, 16#C0, 16#80, 16#41, 16#00, 16#C1, 16#81, 16#40 ],
    LookupCRCLo = [ 16#00, 16#C0, 16#C1, 16#01, 16#C3, 16#03, 16#02, 16#C2, 16#C6, 16#06, 16#07,
            16#C7, 16#05, 16#C5, 16#C4, 16#04, 16#CC, 16#0C, 16#0D, 16#CD, 16#0F, 16#CF, 16#CE, 16#0E, 16#0A, 16#CA, 16#CB, 16#0B, 16#C9,
            16#09, 16#08, 16#C8, 16#D8, 16#18, 16#19, 16#D9, 16#1B, 16#DB, 16#DA, 16#1A, 16#1E, 16#DE, 16#DF, 16#1F, 16#DD, 16#1D, 16#1C,
            16#DC, 16#14, 16#D4, 16#D5, 16#15, 16#D7, 16#17, 16#16, 16#D6, 16#D2, 16#12, 16#13, 16#D3, 16#11, 16#D1, 16#D0, 16#10, 16#F0,
            16#30, 16#31, 16#F1, 16#33, 16#F3, 16#F2, 16#32, 16#36, 16#F6, 16#F7, 16#37, 16#F5, 16#35, 16#34, 16#F4, 16#3C, 16#FC, 16#FD,
            16#3D, 16#FF, 16#3F, 16#3E, 16#FE, 16#FA, 16#3A, 16#3B, 16#FB, 16#39, 16#F9, 16#F8, 16#38, 16#28, 16#E8, 16#E9, 16#29, 16#EB,
            16#2B, 16#2A, 16#EA, 16#EE, 16#2E, 16#2F, 16#EF, 16#2D, 16#ED, 16#EC, 16#2C, 16#E4, 16#24, 16#25, 16#E5, 16#27, 16#E7, 16#E6,
            16#26, 16#22, 16#E2, 16#E3, 16#23, 16#E1, 16#21, 16#20, 16#E0, 16#A0, 16#60, 16#61, 16#A1, 16#63, 16#A3, 16#A2, 16#62, 16#66,
            16#A6, 16#A7, 16#67, 16#A5, 16#65, 16#64, 16#A4, 16#6C, 16#AC, 16#AD, 16#6D, 16#AF, 16#6F, 16#6E, 16#AE, 16#AA, 16#6A, 16#6B,
            16#AB, 16#69, 16#A9, 16#A8, 16#68, 16#78, 16#B8, 16#B9, 16#79, 16#BB, 16#7B, 16#7A, 16#BA, 16#BE, 16#7E, 16#7F, 16#BF, 16#7D,
            16#BD, 16#BC, 16#7C, 16#B4, 16#74, 16#75, 16#B5, 16#77, 16#B7, 16#B6, 16#76, 16#72, 16#B2, 16#B3, 16#73, 16#B1, 16#71, 16#70,
            16#B0, 16#50, 16#90, 16#91, 16#51, 16#93, 16#53, 16#52, 16#92, 16#96, 16#56, 16#57, 16#97, 16#55, 16#95, 16#94, 16#54, 16#9C,
            16#5C, 16#5D, 16#9D, 16#5F, 16#9F, 16#9E, 16#5E, 16#5A, 16#9A, 16#9B, 16#5B, 16#99, 16#59, 16#58, 16#98, 16#88, 16#48, 16#49,
            16#89, 16#4B, 16#8B, 16#8A, 16#4A, 16#4E, 16#8E, 16#8F, 16#4F, 16#8D, 16#4D, 16#4C, 16#8C, 16#44, 16#84, 16#85, 16#45, 16#87,
            16#47, 16#46, 16#86, 16#82, 16#42, 16#43, 16#83, 16#41, 16#81, 16#80, 16#40 ],
    calculateCRC_high_low(BinList, {16#ff, 16#ff}, {LookupCRCHi, LookupCRCLo}).

calculateCRC_high_low([], {High, Low}, _) ->
    {High, Low};
calculateCRC_high_low([H|T], {High, Low}, {LookupCRCHi, LookupCRCLo}) -> 
	Uindex = (High bxor H) + 1,
	NHigh = Low bxor lists:nth(Uindex, LookupCRCHi),
    NLow = lists:nth(Uindex, LookupCRCLo),
    calculateCRC_high_low(T, {NHigh, NLow}, {LookupCRCHi, LookupCRCLo}).

